package jp.sinya.temicontact.service;

import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;

import com.google.gson.Gson;
import com.pubnub.api.PubNub;
import com.pubnub.api.callbacks.SubscribeCallback;
import com.pubnub.api.enums.PNStatusCategory;
import com.pubnub.api.models.consumer.PNStatus;
import com.pubnub.api.models.consumer.pubsub.PNMessageResult;
import com.pubnub.api.models.consumer.pubsub.PNPresenceEventResult;

import java.util.Arrays;

import jp.sinya.temicontact.MyApplication;
import jp.sinya.temicontact.RemoteConnection;
import jp.sinya.temicontact.constants.Constants;
import jp.sinya.temicontact.mvp.model.Message;
import jp.sinya.temicontact.receiver.MyBroadcastReceiver;
import jp.sinya.temicontact.utils.LogUtils;
import jp.sinya.temicontact.utils.PubnubUtils;

import static jp.sinya.temicontact.constants.Constants.RECEIVER_ACTION;

/**
 * @author Koizumi Sinya
 * @date 2018/01/12. 22:31
 * @edithor
 * @date
 */
public class LocalService extends Service {
    private CusServiceConnection conn;
    public PubNub pubnub;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        conn = new CusServiceConnection();
        initPubnub();
    }


    private void initPubnub() {
        pubnub = PubnubUtils.getInstance().getPubNub();
        pubnub.addListener(new SubscribeCallback() {
            @Override
            public void status(PubNub pubnub, PNStatus status) {
                if (status.getCategory() == PNStatusCategory.PNUnexpectedDisconnectCategory) {
                    // This event happens when radio / connectivity is lost
                    LogUtils.Sinya("pubnub PNUnexpectedDisconnectCategory...");

                } else if (status.getCategory() == PNStatusCategory.PNConnectedCategory) {
                    // Connect event. You can do stuff like publish, and know you'll get it.
                    // Or just use the connected event to confirm you are subscribed for
                    // UI / internal notifications, etc

                    if (status.getCategory() == PNStatusCategory.PNConnectedCategory) {

                        LogUtils.Sinya("pubnub PNConnectedCategory...");

                        /*pubnub.publish().channel("awesomeChannel").message("hello!!").async(new PNCallback<PNPublishResult>() {
                            @Override
                            public void onResponse(PNPublishResult result, PNStatus status) {
                                // Check whether request successfully completed or not.
                                if (!status.isError()) {

                                    // Message successfully published to specified channel.
                                }
                                // Request processing failed.
                                else {

                                    // Handle message publish error. Check 'category' property to find out possible issue
                                    // because of which request did fail.
                                    //
                                    // Request can be resent using: [status retry];
                                }
                            }
                        });*/
                    }
                } else if (status.getCategory() == PNStatusCategory.PNReconnectedCategory) {
                    LogUtils.Sinya("pubnub PNReconnectedCategory...");
                    // Happens as part of our regular operation. This event happens when
                    // radio / connectivity is lost, then regained.

                } else if (status.getCategory() == PNStatusCategory.PNDecryptionErrorCategory) {
                    LogUtils.Sinya("pubnub PNDecryptionErrorCategory...");
                    // Handle messsage decryption error. Probably client configured to
                    // encrypt messages and on live data feed it received plain text.
                }
            }

            @Override
            public void message(PubNub pubnub, PNMessageResult message) {
                // Handle new message stored in message.message

                String objJson = message.getMessage().toString();
                Message msg = new Gson().fromJson(objJson, Message.class);

                //为了过滤自己接收消息， 截断弹出notification
                if (!msg.id.equals(MyApplication.id)) {
                    Intent intent = new Intent(LocalService.this, MyBroadcastReceiver.class);
                    intent.setAction(RECEIVER_ACTION);
                    intent.putExtra("message", msg.msg);
                    sendBroadcast(intent);
                }

                if (message.getChannel() != null) {
                    // Message has been received on channel group stored in
                    // message.getChannel()
                } else {
                    // Message has been received on channel stored in
                    // message.getSubscription()
                }

            /*
            log the following items with your favorite logger
                - message.getMessage()
                - message.getSubscription()
                - message.getTimetoken()
            */
            }

            @Override
            public void presence(PubNub pubnub, PNPresenceEventResult presence) {
                LogUtils.Sinya("presence");
            }
        });

        pubnub.subscribe().channels(Arrays.asList(Constants.CHANNEL_NAME)).execute();

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        LogUtils.Sinya("onStartCommand local start...");
        this.bindService(new Intent(LocalService.this, RemoteService.class), conn, Context.BIND_IMPORTANT);

        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        this.bindService(new Intent(LocalService.this, RemoteService.class), conn, Context.BIND_IMPORTANT);
        this.startService(new Intent(LocalService.this, RemoteService.class));
    }

    /**
     * Service内部代理
     */
    class MyBinder extends RemoteConnection.Stub {

        @Override
        public String getPackageName() throws RemoteException {
            return "LocalService";
        }
    }


    class CusServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            LogUtils.Sinya("connect with remote service");
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            LogUtils.Sinya("disconnect with remote service");
            LocalService.this.bindService(new Intent(LocalService.this, RemoteService.class), conn, Context.BIND_IMPORTANT);
            LocalService.this.startService(new Intent(LocalService.this, RemoteService.class));
        }
    }
}
